
#include "RtBase.h"
#include "RtUtilClasses.h"
#include "RtThreadManager.h"

///////////////////////////////////////////////////////////////
// class CRtEnsureSingleThread
///////////////////////////////////////////////////////////////

CRtEnsureSingleThread::CRtEnsureSingleThread()
	: m_ThreadIdOpen(CRtThreadManager::GetThreadSelfId())
{
}

void CRtEnsureSingleThread::EnsureSingleThread() const 
{
#ifdef RT_DEBUG
	RT_THREAD_ID tidCur = CRtThreadManager::GetThreadSelfId();
	//RT_ASSERTE(CRtThreadManager::IsThreadEqual(m_ThreadIdOpen, tidCur));
	if (!CRtThreadManager::IsThreadEqual(m_ThreadIdOpen, tidCur))
	{
		RT_ERROR_TRACE_THIS("CRtEnsureSingleThread::EnsureSingleThread, ASSERT failed! m_ThreadIdOpen="
			<<m_ThreadIdOpen<<",tidCur="<<tidCur);
	}
#endif // RT_DEBUG
}

void CRtEnsureSingleThread::Reset2CurrentThreadId()
{
	m_ThreadIdOpen = CRtThreadManager::GetThreadSelfId();
	RT_INFO_TRACE_THIS("CRtEnsureSingleThread::Reset2CurrentThreadId: "<<m_ThreadIdOpen);
}

void CRtEnsureSingleThread::Reset2ThreadId(RT_THREAD_ID aTid)
{
	m_ThreadIdOpen = aTid;
	RT_INFO_TRACE_THIS("CRtEnsureSingleThread::Reset2ThreadId: "<<m_ThreadIdOpen);
}


///////////////////////////////////////////////////////////////
// class CRtSignalStop
///////////////////////////////////////////////////////////////

CRtSignalStop CRtSignalStop::s_rtSignalStopSingleton;

CRtSignalStop::CRtSignalStop()
	: m_pThread(NULL)
{
}

CRtSignalStop::~CRtSignalStop()
{
}

CRtSignalStop* CRtSignalStop::Instance()
{
	return &s_rtSignalStopSingleton;
}

RtResult CRtSignalStop::Launch(int aSig)
{
	RtResult rv = RT_ERROR_FAILURE;

#ifdef RT_WIN32
	CRtThread *pMain = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_MAIN);
	if (pMain) {
		rv = pMain->Stop();
		RT_ASSERTE(RT_SUCCEEDED(rv));
	}
#else // !RT_WIN32
	if (m_pThread) {
		// Signal has posted, ignore it.
		return RT_OK;
	}

	CRtThread *pNetwork = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_NETWORK);
	// can't stop main thread directly in Linux 
	// due to dead lock of condition variable.
	if (!pNetwork) 
		return rv;
	
	// every thread will invoke this signal roution in Linux.
	// only the network thread allows post event int the signal roution.
	/*if (!CRtThreadManager::IsEqualCurrentThread(pNetwork->GetThreadId())) 
		return RT_OK;*/
	m_pThread = pNetwork;

	IRtEventQueue *pEq = m_pThread->GetEventQueue();
	if (pEq) {
		rv = pEq->PostEvent(this);
		//::printf("CRtSignalStop::CRtSignalStop, PostEvent, rv=%d.\n", (int)rv);
	}
#endif // RT_WIN32
	return rv;
}

RtResult CRtSignalStop::OnEventFire()
{
	CRtThread *pMain = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_MAIN);
	if (pMain)
		return pMain->Stop();
	else
		return RT_ERROR_NULL_POINTER;
}

void CRtSignalStop::OnDestorySelf()
{
	// don't delete this
}


///////////////////////////////////////////////////////////////
// class CRtCleanUpBase
///////////////////////////////////////////////////////////////

CRtCleanUpBase* CRtCleanUpBase::s_pHeader = NULL;

static int s_nRef = 0;
CRtCleanUpBase::CRtCleanUpBase()
{	
	MutexType *pMutex = NULL;
	CRtThreadManager::Instance()->GetSingletonMutex(pMutex);
	RT_ASSERTE(pMutex);

	CRtMutexGuardT<MutexType> theGuard(*pMutex);
	m_pNext = s_pHeader;
	s_pHeader = this;

	s_nRef++;
	RT_INFO_TRACE("CRtCleanUpBase::CRtCleanUpBase, Item: "<<s_nRef<<", this: "<<this);
}

CRtCleanUpBase::~CRtCleanUpBase()
{
}

void CRtCleanUpBase::CleanUp()
{
	delete this;
}

void CRtCleanUpBase::CleanupAll()
{
	MutexType *pMutex = NULL;
	CRtThreadManager::Instance()->GetSingletonMutex(pMutex);
	RT_ASSERTE(pMutex);

	CRtMutexGuardT<MutexType> theGuard(*pMutex);
	while (s_pHeader) 
	{
		RT_INFO_TRACE("CRtCleanUpBase::CleanupAll, Item: "<<s_nRef<<", this: "<<s_pHeader);
		s_nRef--;
		CRtCleanUpBase *pTmp = s_pHeader->m_pNext;
		s_pHeader->CleanUp();
		s_pHeader = pTmp;
	}
}


///////////////////////////////////////////////////////////////
// class CRtDataBlockNoMalloc
///////////////////////////////////////////////////////////////

CRtDataBlockNoMalloc::CRtDataBlockNoMalloc(LPCSTR aStr, DWORD aLen)
	: m_pBegin(aStr)
	, m_pEnd(aStr + aLen)
	, m_pCurrentRead(m_pBegin)
	, m_pCurrentWrite(const_cast<LPSTR>(m_pBegin))
{
	RT_ASSERTE(m_pBegin);
}

RtResult CRtDataBlockNoMalloc::
Read(LPVOID aDst, DWORD aCount, DWORD *aBytesRead)
{
	RT_ASSERTE_RETURN(aDst, RT_ERROR_INVALID_ARG);
	RT_ASSERTE_RETURN(m_pCurrentRead, RT_ERROR_NOT_INITIALIZED);
	RT_ASSERTE(m_pCurrentRead <= m_pEnd);
	
	DWORD dwLen = RT_MIN(aCount, static_cast<DWORD>(m_pCurrentRead - m_pEnd));
	if (dwLen > 0) {
		::memcpy(aDst, m_pCurrentRead, dwLen);
		m_pCurrentRead += dwLen;
	}
	if (aBytesRead)
		*aBytesRead = dwLen;
	return dwLen == aCount ? RT_OK : RT_ERROR_PARTIAL_DATA;
}

RtResult CRtDataBlockNoMalloc::
Write(LPCVOID aSrc, DWORD aCount, DWORD *aBytesWritten)
{
	RT_ASSERTE_RETURN(aSrc, RT_ERROR_INVALID_ARG);
	RT_ASSERTE_RETURN(m_pCurrentWrite, RT_ERROR_NOT_INITIALIZED);
	RT_ASSERTE(m_pCurrentWrite <= m_pEnd);

	DWORD dwLen = RT_MIN(aCount, static_cast<DWORD>(m_pEnd - m_pCurrentWrite));
	if (dwLen > 0) {
		::memcpy(m_pCurrentWrite, aSrc, dwLen);
		m_pCurrentWrite += dwLen;
	}
	if (aBytesWritten)
		*aBytesWritten = dwLen;
	return dwLen == aCount ? RT_OK : RT_ERROR_PARTIAL_DATA;
}


///////////////////////////////////////////////////////////////
// class CRtDataBlockNoMalloc
///////////////////////////////////////////////////////////////

void CRtStopFlag::SetStartFlag()
{
	m_Est.EnsureSingleThread();
	RT_ASSERTE(m_bStoppedFlag);
	m_bStoppedFlag = FALSE;
}

void CRtStopFlag::SetStopFlag()
{
	m_Est.EnsureSingleThread();
	m_bStoppedFlag = TRUE;
}

